/*******************************************************************************
 * Copyright (c) 2000, 2007 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************//*

package org.eclipse.jface.text;


import org.eclipse.core.runtime.Assert;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;


*/
/**
 * Default implementation of {@link IDocumentAdapter}.
 * <p>
 * <strong>Note:</strong> This adapter does not work if the widget auto-wraps the text.
 * </p>
 *//*

public class DocumentAdapter implements IDocumentListener, IDocumentAdapterExtension {

    */
/**
     * The adapted document.
     *//*

    private IDocument fDocument;
    */
/**
     * The document clone for the non-forwarding case.
     *//*

    private IDocument fDocumentClone;
    */
/**
     * The original content
     *//*

    private String fOriginalContent;
    */
/**
     * The original line delimiters
     *//*

    private String[] fOriginalLineDelimiters;
    */
/**
     * The registered text change listeners
     *//*

    private final List<TextChangeListener> fTextChangeListeners = new ArrayList<>(1);
    */
/**
     * The remembered document event
     *
     * @since 2.0
     *//*

    private DocumentEvent fEvent;
    */
/**
     * The line delimiter
     *//*

    private String fLineDelimiter = null;
    */
/**
     * Indicates whether this adapter is forwarding document changes
     *
     * @since 2.0
     *//*

    private boolean fIsForwarding = true;
    */
/**
     * Length of document at receipt of <code>documentAboutToBeChanged</code>
     *
     * @since 2.1
     *//*

    private int fRememberedLengthOfDocument;
    */
/**
     * Length of first document line at receipt of <code>documentAboutToBeChanged</code>
     *
     * @since 2.1
     *//*

    private int fRememberedLengthOfFirstLine;
    */
/**
     * The data of the event at receipt of <code>documentAboutToBeChanged</code>
     *
     * @since 2.1
     *//*

    private final DocumentEvent fOriginalEvent = new DocumentEvent();
    private boolean editable = true;
    private boolean isBatchEdit;

    */
/**
     * Creates a new document adapter which is initially not connected to
     * any document.
     *//*

    public DocumentAdapter() {
        setDocument(new Document());
    }

    */
/**
     * Tries to repair the line information.
     *
     * @param document the document
     * @see IRepairableDocument#repairLineInformation()
     * @since 3.0
     *//*

    private static void repairLineInformation(IDocument document) {
        if (document instanceof IRepairableDocument) {
            IRepairableDocument repairable = (IRepairableDocument) document;
            repairable.repairLineInformation();
        }
    }

    */
/**
     * Returns the line for the given line number.
     *
     * @param document the document
     * @param line     the line number
     * @return the content of the line of the given number in the given document
     * @throws BadLocationException if the line number is invalid for the adapted document
     * @since 3.0
     *//*

    private static String doGetLine(IDocument document, int line) throws BadLocationException {
        IRegion r = document.getLineInformation(line);
        return document.get(r.getOffset(), r.getLength());
    }

    public boolean isBatchEdit() {
        return isBatchEdit;
    }

    public void setBatchEdit(boolean isBatchEdit) {
        this.isBatchEdit = isBatchEdit;
        if (!isBatchEdit)
            fireTextChanged();
    }

    public boolean isEditable() {
        return editable;
    }

    public void setEditable(boolean editable) {
        this.editable = editable;
    }

    public IDocument getDocument() {
        return fDocument;
    }

    */
/**
     * Sets the given document as the document to be adapted.
     *
     * @param document the document to be adapted or <code>null</code> if there is no document
     *//*

    public void setDocument(IDocument document) {

        if (fDocument != null)
            fDocument.removePrenotifiedDocumentListener(this);

        fDocument = document;
        fLineDelimiter = null;

        if (!fIsForwarding) {
            fDocumentClone = null;
            if (fDocument != null) {
                fOriginalContent = fDocument.get();
                fOriginalLineDelimiters = fDocument.getLegalLineDelimiters();
            } else {
                fOriginalContent = null;
                fOriginalLineDelimiters = null;
            }
        }

        if (fDocument != null)
            fDocument.addPrenotifiedDocumentListener(this);
    }

    public FindReplaceDocumentAdapter find() {
        return new FindReplaceDocumentAdapter(fDocument);
    }

    public String getText() {
        return fDocument.get();
    }

    public void setText(String text) {
        fDocument.set(text);
    }

    public void addTextChangeListener(TextChangeListener listener) {
        Assert.isNotNull(listener);
        if (!fTextChangeListeners.contains(listener))
            fTextChangeListeners.add(listener);
    }

    public void removeTextChangeListener(TextChangeListener listener) {
        Assert.isNotNull(listener);
        fTextChangeListeners.remove(listener);
    }

    private IDocument getDocumentForRead() {
        if (!fIsForwarding) {
            if (fDocumentClone == null) {
                String content = fOriginalContent == null ? "" : fOriginalContent; //$NON-NLS-1$
                String[] delims = fOriginalLineDelimiters == null ? DefaultLineTracker.DELIMITERS : fOriginalLineDelimiters;
                fDocumentClone = new DocumentClone(content, delims);
            }
            return fDocumentClone;
        }

        return fDocument;
    }

    public char getChar(int index) {
        try {
            return getDocumentForRead().getChar(index);
        } catch (BadLocationException e) {
            return 0;
        }
    }

    public String getLine(int line) {

        IDocument document = getDocumentForRead();
        try {
            return doGetLine(document, line);
        } catch (BadLocationException x) {
            repairLineInformation(document);
            try {
                return doGetLine(document, line);
            } catch (BadLocationException x2) {
                return x2.getMessage();
            }
        }
        //return null;
    }

    public int getLineAtOffset(int offset) {
        IDocument document = getDocumentForRead();
        try {
            return document.getLineOfOffset(offset);
        } catch (BadLocationException x) {
            repairLineInformation(document);
            try {
                return document.getLineOfOffset(offset);
            } catch (BadLocationException x2) {
            }
        }
        return -1;
    }

    public int getLineCount() {
        return getDocumentForRead().getNumberOfLines();
    }

    public int getOffsetAtLine(int line) {
        IDocument document = getDocumentForRead();
        try {
            return document.getLineOffset(line);
        } catch (BadLocationException x) {
            repairLineInformation(document);
            try {
                return document.getLineOffset(line);
            } catch (BadLocationException x2) {
            }
        }

        return -1;
    }

    public String getTextRange(int offset, int length) {
        try {
            return getDocumentForRead().get(offset, length);
        } catch (BadLocationException x) {
            return null;
        }
    }

    public void replaceTextRange(int pos, int length, String text) {
        if (editable)
            try {
                fDocument.replace(pos, length, text);
            } catch (BadLocationException x) {
            }
    }

    public int getCharCount() {
        return getDocumentForRead().getLength();
    }

    public String getLineDelimiter() {
        if (fLineDelimiter == null)
            fLineDelimiter = TextUtilities.getDefaultLineDelimiter(fDocument);
        return fLineDelimiter;
    }

    @Override
    public void documentChanged(DocumentEvent event) {
        // check whether the given event is the one which was remembered
        if (fEvent == null || event != fEvent)
            return;

        if (isPatchedEvent(event) || (event.getOffset() == 0 && event.getLength() == fRememberedLengthOfDocument)) {
            fLineDelimiter = null;
            fireTextSet();
        } else {
            if (event.getOffset() < fRememberedLengthOfFirstLine)
                fLineDelimiter = null;
            fireTextChanged();
        }
    }

    @Override
    public void documentAboutToBeChanged(DocumentEvent event) {

        fRememberedLengthOfDocument = fDocument.getLength();
        try {
            fRememberedLengthOfFirstLine = fDocument.getLineLength(0);
        } catch (BadLocationException e) {
            fRememberedLengthOfFirstLine = -1;
        }

        fEvent = event;
        rememberEventData(fEvent);
        fireTextChanging();
    }

    */
/**
     * Checks whether this event has been changed between <code>documentAboutToBeChanged</code> and
     * <code>documentChanged</code>.
     *
     * @param event the event to be checked
     * @return <code>true</code> if the event has been changed, <code>false</code> otherwise
     *//*

    private boolean isPatchedEvent(DocumentEvent event) {
        return fOriginalEvent.fOffset != event.fOffset || fOriginalEvent.fLength != event.fLength || fOriginalEvent.fText != event.fText;
    }

    */
/**
     * Makes a copy of the given event and remembers it.
     *
     * @param event the event to be copied
     *//*

    private void rememberEventData(DocumentEvent event) {
        fOriginalEvent.fOffset = event.fOffset;
        fOriginalEvent.fLength = event.fLength;
        fOriginalEvent.fText = event.fText;
    }

    */
/**
     * Sends a text changed event to all registered listeners.
     *//*

    private void fireTextChanged() {

        if (!fIsForwarding)
            return;

        if (fTextChangeListeners != null && fTextChangeListeners.size() > 0) {
            Iterator<TextChangeListener> e = new ArrayList<TextChangeListener>(fTextChangeListeners).iterator();
            while (e.hasNext())
                e.next().textChanged();
        }
    }

    */
/**
     * Sends a text set event to all registered listeners.
     *//*

    private void fireTextSet() {

        if (!fIsForwarding)
            return;

        if (fTextChangeListeners != null && fTextChangeListeners.size() > 0) {
            Iterator<TextChangeListener> e = new ArrayList<TextChangeListener>(fTextChangeListeners).iterator();
            while (e.hasNext())
                e.next().textSet();
        }
    }

    */
/**
     * Sends the text changing event to all registered listeners.
     *//*

    private void fireTextChanging() {

        if (!fIsForwarding)
            return;

        try {
            IDocument document = fEvent.getDocument();
            if (document == null)
                return;

            TextChangingEvent event = new TextChangingEvent();
            event.start = fEvent.fOffset;
            event.replaceCharCount = fEvent.fLength;
            event.replaceLineCount = document.getNumberOfLines(fEvent.fOffset, fEvent.fLength) - 1;
            event.newText = fEvent.fText;
            event.newCharCount = (fEvent.fText == null ? 0 : fEvent.fText.length());
            event.newLineCount = (fEvent.fText == null ? 0 : document.computeNumberOfLines(fEvent.fText));

            if (fTextChangeListeners != null && fTextChangeListeners.size() > 0) {
                Iterator<TextChangeListener> e = new ArrayList<TextChangeListener>(fTextChangeListeners).iterator();
                while (e.hasNext())
                    e.next().textChanging(event);
            }

        } catch (BadLocationException e) {
        }
    }

    public void resumeForwardingDocumentChanges() {
        fIsForwarding = true;
        fDocumentClone = null;
        fOriginalContent = null;
        fOriginalLineDelimiters = null;
        fireTextSet();
    }

    public void stopForwardingDocumentChanges() {
        fDocumentClone = null;
        fOriginalContent = fDocument.get();
        fOriginalLineDelimiters = fDocument.getLegalLineDelimiters();
        fIsForwarding = false;
    }
}
*/
